
package com.ohos.connect.devicecloud.dev.modular.sms.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ohos.connect.devicecloud.common.exception.CommonException;
import com.ohos.connect.devicecloud.dev.api.DevConfigApi;
import lombok.extern.slf4j.Slf4j;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 华为云短信工具类
 * 参考文档：https://support.huaweicloud.com/api-msgsms/sms_05_0001.html
     **/
@Slf4j
public class DevSmsHuaWeiYunUtil {

    //无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
    private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
    //无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
    private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";


    //APP_Key
    private static final String OHOSCONAC_SMS_HWYUN_ACCESS_KEY_ID_KEY = "OHOSCONAC_SMS_HWYUN_ACCESS_KEY_ID";
    //APP_Secret
    private static final String OHOSCONAC_SMS_HWYUN_ACCESS_KEY_SECRET_KEY = "OHOSCONAC_SMS_HWYUN_ACCESS_KEY_SECRET";

    private static final String OHOSCONAC_SMS_HWYUN_END_POINT_KEY = "OHOSCONAC_SMS_HWYUN_END_POINT";
    //签名名称
    private static final String OHOSCONAC_SMS_HWYUN_DEFAULT_SIGN_NAME_KEY = "OHOSCONAC_SMS_HWYUN_DEFAULT_SIGN_NAME";


    private static String accessKeyId = "";

    private static String accessKeySecret = "";

    private static String endpoint = "";

    //国内短信签名通道号 需要生态公司申请 签名时获取
    private static String sender = "";

    /**
     * 初始化操作的客户端
     *
     *
     */
    private static void initClient() {

        DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);

        /* accessKeyId */
        accessKeyId = devConfigApi.getValueByKey(OHOSCONAC_SMS_HWYUN_ACCESS_KEY_ID_KEY);

        if(ObjectUtil.isEmpty(accessKeyId)) {
            throw new CommonException("华为云短信操作客户端未正确配置：accessKeyId为空");
        }

        /* accessKeySecret */
        accessKeySecret = devConfigApi.getValueByKey(OHOSCONAC_SMS_HWYUN_ACCESS_KEY_SECRET_KEY);

        if(ObjectUtil.isEmpty(accessKeySecret)) {
            throw new CommonException("华为云短信操作客户端未正确配置：accessKeySecret为空");
        }

        /* endpoint */
         endpoint = devConfigApi.getValueByKey(OHOSCONAC_SMS_HWYUN_END_POINT_KEY);

        if(ObjectUtil.isEmpty(endpoint)) {
            throw new CommonException("华为云云短信操作客户端未正确配置：endpoint为空");
        }
        /* sender */

        sender = devConfigApi.getValueByKey(OHOSCONAC_SMS_HWYUN_DEFAULT_SIGN_NAME_KEY);

        if(ObjectUtil.isEmpty(sender)) {
            throw new CommonException("华为云云短信操作客户端未正确配置：sender为空");
        }

    }

    /**
     * 发送短信
     *
     * @param phoneNumbers 手机号码，支持对多个手机号码发送短信，手机号码之间以半角逗号（,）分隔。
     *                     上限为1000个手机号码。批量调用相对于单条调用及时性稍有延迟。
     * @param signName 短信服务控制台配置且审核通过的短信签名
     * @param templateCode 短信服务控制台配置且审核通过的模板编码
     * @param templateParams 短信模板变量对应的实际值，JSON格式。支持传入多个参数，示例：{"name":"张三","number":"15038****76"}
     *
     * @return 发送的结果信息集合
     *
     **/
    public static String sendSms(String phoneNumbers, String signName, String templateCode, String[] templateParams) {
        try {
            initClient();
            if(ObjectUtil.isEmpty(signName)) {
                // 签名为空，则获取默认签名
                DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
                signName = devConfigApi.getValueByKey(OHOSCONAC_SMS_HWYUN_DEFAULT_SIGN_NAME_KEY);
                if(ObjectUtil.isEmpty(signName)) {
                    throw new CommonException("华为云短信操作客户端未正确配置：signName为空");
                }
            }


//            endpoint = "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendDiffSms/v1";
//            accessKeyId="brZH863n57ZcdFOV9OrfUELeLdxx";
//            accessKeySecret="nuVgiFl9jteLiNHJPpMT0ZH4oNqQ";
//            sender = "1069368924410007545";
            String statusCallBack = "";

            //{"smsContent":[{"templateParas":["66577"],"signature":"华为云短信测试","to":["+8618682178808"],"templateId":"4fd36d9eb91f4501970a345f3dea7016"}],"from":"1069368924410007545"}
            String body = buildRequestBodyBatch(phoneNumbers.split(StrUtil.COMMA),sender,signName,templateCode,templateParams,statusCallBack);
            log.debug(body);

            if (null == body || body.isEmpty()) {
                throw new CommonException("华为云短信操作发送短信失败！：body is null");
            }

            //请求Headers中的X-WSSE参数值
            String wsseHeader = buildWsseHeader(accessKeyId, accessKeySecret);
            if (BeanUtil.isEmpty(wsseHeader)) {
                throw new CommonException("华为云短信操作发送短信失败！：wsse header is null.");
            }

            trustAllHttpsCertificates();

            HttpRequest httpRequest = HttpRequest.post(endpoint);

            httpRequest.setHostnameVerifier( (hostname , session)-> {
                return true;
            });
            Map<String,String> heads = new HashMap<>();
            heads.put("Authorization", AUTH_HEADER_VALUE);
            heads.put("Content-Type","application/json");
            heads.put("X-WSSE",wsseHeader);
            httpRequest.headerMap(heads,true);

            httpRequest.body(body);

            HttpResponse response = httpRequest.execute();
            String responseBody = response.body();
            log.debug( httpRequest.getMethod() +"Status: "+ response.getStatus() +" Resp: "+responseBody);

            if(response.getStatus() != 200) {
                throw new CommonException("华为云短信操作发送短信失败!!"+ errorMsg( response.getStatus() ,responseBody));
            }

            return responseBody;

        } catch (Exception e) {
            throw new CommonException(e.getMessage());
        }
    }


    private static String buildRequestBodyBatch(String[] phoneNumbers, String sender,String signName, String templateCode, String[] templateParams,
                                                String statusCallBack) {
        //smsContent,不携带签名名称时,signature请填null
        List<Map<String, Object>> smsContent = new ArrayList<Map<String, Object>>();
        Map<String, Object> item = initDiffSms(phoneNumbers, templateCode, templateParams, signName);

        if (null != item && !item.isEmpty()) {
            smsContent.add(item);
        }

        if (null == sender || null == smsContent || sender.isEmpty() || smsContent.isEmpty()) {
            throw new CommonException("buildRequestBody(): sender or smsContent is null.");
        }
        JSONArray jsonArr = new JSONArray();

        for(Map<String, Object> it: smsContent){
            jsonArr.put(it);
        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("from", sender);
        data.put("smsContent", jsonArr);
        if (null != statusCallBack && !statusCallBack.isEmpty()) {
            data.put("statusCallback", statusCallBack);
        }

        return new JSONObject(data).toString();
    }




    /**
     * 构造smsContent参数值
     * @param receiver
     * @param templateId
     * @param templateParas
     * @param signature | 签名名称,使用国内短信通用模板时填写
     * @return
     */
   private static Map<String, Object> initDiffSms(String[] receiver, String templateId, String[] templateParas,
                                           String signature) {
        if (null == receiver || null == templateId || receiver.length == 0 || templateId.isEmpty()) {
            throw new CommonException("initDiffSms(): receiver or templateId is null.");
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("to", receiver);
        map.put("templateId", templateId);
        if (null != templateParas && templateParas.length > 0) {
            map.put("templateParas", templateParas);
        }
        if (null != signature && !signature.isEmpty()) {
            map.put("signature", signature);
        }

        return map;
   }



    /**
     * 构造X-WSSE参数值
     * @param appKey
     * @param appSecret
     * @return
     */
    private static String buildWsseHeader(String appKey, String appSecret) {
        if (null == appKey || null == appSecret || appKey.isEmpty() || appSecret.isEmpty()) {
            System.out.println("buildWsseHeader(): appKey or appSecret is null.");
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        String time = sdf.format(new Date()); //Created
        String nonce = UUID.randomUUID().toString().replace("-", ""); //Nonce

        MessageDigest md;
        byte[] passwordDigest = null;

        try {
            md = MessageDigest.getInstance("SHA-256");
            md.update((nonce + time + appSecret).getBytes());
            passwordDigest = md.digest();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        //如果JDK版本是1.8,请加载原生Base64类,并使用如下代码
        String passwordDigestBase64Str = Base64.getEncoder().encodeToString(passwordDigest); //PasswordDigest
        //如果JDK版本低于1.8,请加载三方库提供Base64类,并使用如下代码
        //String passwordDigestBase64Str = Base64.encodeBase64String(passwordDigest); //PasswordDigest
        //若passwordDigestBase64Str中包含换行符,请执行如下代码进行修正
        //passwordDigestBase64Str = passwordDigestBase64Str.replaceAll("[\\s*\t\n\r]", "");
        return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
    }

    /*** @throws Exception
     */
    private static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[] {
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return;
                    }
                    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return;
                    }
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                }
        };
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    }


    private static String errorMsg(int status,String respBody ) {
        String bodyCode = JSONUtil.parseObj(respBody).getStr("code");
//        String msg = respBody;
//        switch (status){
//            case 400:
//                switch (bodyCode){
//                    case "E000503":
//                        // 参数传入与模版不匹配
//                        // Status: 400 Resp:{"code":"E000503","description":"The parameter format is incorrect.The SMS template is required."}
//                        msg = "参数格式与短信不匹配！";
//                        break;
//                    case "E000000":
//                        msg = "System error.";
//                        break;
//                }
//                break;
//
//        }
        return String.format("{\"status\":%d,\"code\":\"%s\",\"msg\":%s}",status,bodyCode,respBody);
    }



}
